package com.zis.wechat.api.inter.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zis.common.AuctProperties;
import com.zis.core.ResponseEntity;
import com.zis.utils.*;
import com.zis.wechat.api.config.WechatAPI;
import com.zis.wechat.api.config.WxConstant;
import com.zis.wechat.api.inter.IWechatInter;
import com.zis.wechat.api.model.RespMsgTxt;
import com.zis.wechat.model.Account;
import com.zis.wechat.utils.Sign;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * Create by wangshen 2018/1/2
 */
@Service
@Transactional("txManager")
public class WechatInterImpl implements IWechatInter {

    private static final Logger logger = LoggerFactory.getLogger(WechatInterImpl.class);

    @Autowired
    @Qualifier("auctProperties")
    private AuctProperties auctProperties;

    @Autowired
    @Qualifier("redisTemplate")
    private RedisTemplate redisTemplate;

    private long LOGIN_INVALID_TIME = 100*60L;

    /**
     * 获取公众号accessToken
     * @param accountId
     * @return
     */
    @Override
    public String getAccessToken(String accountId) throws Exception {
        if(accountId.equals("")){
            return null;
        }
        String url;
        String result;
        JSONObject jsonObj;
        String accessToken = String.valueOf(redisTemplate.opsForHash().get(WxConstant.WECHAT_ACCESS_TOKEN_KEY,accountId));
        if(accessToken==null||accessToken.equals("")){//获取accessToken
            jsonObj = getNewAccessToken(accountId);
            if (jsonObj == null) return null;
            accessToken = jsonObj.getString("access_token");
            redisTemplate.opsForHash().put(WxConstant.WECHAT_ACCESS_TOKEN_KEY,accountId,accessToken);
        }
        //验证token是否有效
        url = WechatAPI.getWechatServIP(accessToken);
        result =  HttpUtil.httpRequest(url,HttpUtil.METHOD_TYPE_GET,null);
        jsonObj = JSON.parseObject(result);
        if(jsonObj.containsKey("errcode")){
            logger.error(" >>> 校验accessToken错误："+ WxConstant.GLOBAL_ERROR_CODE.get(jsonObj.get("errcode")));
            jsonObj = getNewAccessToken(accountId);
            if (jsonObj == null) return null;
            accessToken = jsonObj.getString("access_token");
            redisTemplate.opsForHash().put(WxConstant.WECHAT_ACCESS_TOKEN_KEY,accountId,accessToken);
        }
        return accessToken;
    }

    /**
     * 关注欢迎消息
     * @param accountId
     * @param openId
     * @return
     * @throws Exception
     */
    @Override
    public String focusMsg(String accountId, String openId) throws Exception {
        Account account = (Account) redisTemplate.opsForHash().get(WxConstant.WECHAT_ACCOUNT_KEY, accountId);
        //发送一条欢迎语
        RespMsgTxt respMsgTxt = new RespMsgTxt();
        respMsgTxt.setToUserName(openId);
        respMsgTxt.setFromUserName(account.getOriginalId());//微信原始ID
        respMsgTxt.setContent("欢迎关注！");
        return XmlUtils.msgEncapsulation(respMsgTxt);
    }

    /**
     * 菜单创建
     * @param accountId
     * @param menuObj
     * @return
     * @throws Exception
     */
    @Override
    public String createMenu(String accountId, JSONObject menuObj) throws Exception {
        String accessToken = this.getAccessToken(accountId);
        String url = WechatAPI.menuCreateUrl(accessToken);
        String result = HttpRequest.doPost(url,menuObj.toJSONString());
        JSONObject jsonObj = JSON.parseObject(result);
        if(jsonObj.containsKey("errcode")&&!jsonObj.getString("errcode").equals("0")){
            logger.error(" >>> 创建菜单错误："+ jsonObj.toJSONString());
            return ResponseEntity.createErrorJsonResponse(jsonObj.getString("errmsg"));
        }
        return ResponseEntity.createNormalJsonResponse("菜单发布成功");
    }

    /**
     * 获取js-sdk签名
     * @param accountId
     * @return
     * @throws Exception
     */
    @Override
    public String JsApiToken(String accountId) throws Exception {
        String ticket = "";
        if (!redisTemplate.hasKey(WxConstant.WECHAT_JSSDK_TICKET)) {
            //不存在重新写入
            String accessToken = this.getAccessToken(accountId);
            String result = HttpUtil.httpRequest(WechatAPI.jsSdkToken(accessToken), HttpUtil.METHOD_TYPE_GET, null);
            JSONObject jsonObj = JSON.parseObject(result);
            if(jsonObj.containsKey("errcode")&&jsonObj.getString("errcode").equals("0")){
               ticket = jsonObj.getString("ticket");
               redisTemplate.opsForValue().set(WxConstant.WECHAT_JSSDK_TICKET, ticket);
               redisTemplate.expire(WxConstant.WECHAT_JSSDK_TICKET, LOGIN_INVALID_TIME, TimeUnit.SECONDS);
            }
        }
        Account account = (Account) redisTemplate.opsForHash().get(WxConstant.WECHAT_ACCOUNT_KEY, accountId);
        ticket = redisTemplate.opsForValue().get(WxConstant.WECHAT_JSSDK_TICKET).toString();
        if (ticket!=null&&!ticket.equals("")) {
            Map<String, String> map = Sign.sign(ticket, auctProperties.getHost());
            map.put("appId", account.getAppid());
            return ResponseEntity.createNormalJsonResponse(JSONObject.parseObject(JSON.toJSONString(map)));
        }
        return ResponseEntity.createErrorJsonResponse("签名获取失败");
    }

    //====================抽离的方法====================//
    /**
     * 获取新的accessToken
     * @param accountId
     * @return
     */
    private JSONObject getNewAccessToken(String accountId) {
        String url;
        String result;
        JSONObject jsonObj;
        Account account = (Account) redisTemplate.opsForHash().get(WxConstant.WECHAT_ACCOUNT_KEY, accountId);
        url = WechatAPI.accessTokenUrl(account.getAppid(),account.getAppsecret());
        result = HttpUtil.httpRequest(url, HttpUtil.METHOD_TYPE_GET,null);
        jsonObj = JSON.parseObject(result);
        if(jsonObj.containsKey("errcode")&&!jsonObj.get("errcode").equals("0")){
            logger.error(" >>> 获取新的accessToken错误："+ jsonObj.toJSONString());
            return null;
        }
        return jsonObj;
    }
}
